home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / capturing / softvdig / softvdig.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  32.1 KB  |  1,146 lines

  1. /*
  2.     File:        softVdig.c
  3.  
  4.     Contains:    Software video digitzer routines
  5.  
  6.     Written by:    Peter Hoddie (mostly) and Casey King and Gary Woodcock
  7.     
  8.                 Refer to develop Issue 14, "Video Digitizing Under QuickTime",
  9.                 for details on this code.
  10.                 
  11.                 This code requires QuickTime 1.5.
  12.  
  13.     Copyright:    © 1993 by Apple Computer, Inc.
  14.  
  15. */
  16.  
  17. //-----------------------------------------------------------------------
  18. // includes
  19.  
  20. #include "softVdig.h"
  21. #include <FixMath.h>
  22. #include <Errors.h>
  23. #include <Packages.h>
  24. #include <Fonts.h>
  25. #include <MacMemory.h>
  26. #include <ToolUtils.h>
  27. #include <NumberFormatting.h>
  28.  
  29. //-----------------------------------------------------------------------
  30.  
  31. #if TARGET_OS_WIN32
  32.     #pragma warning (disable: 4761)        // ignore integral size mismatch in argument
  33. #endif
  34.  
  35. #if defined(DEBUG_IT) || !TARGET_OS_MAC
  36. // Use this declaration when we're running linked (for debugging)
  37. pascal ComponentResult softVdig (ComponentParameters *params, Handle storage)
  38.  
  39. #else
  40.  
  41. // Use this declaration when we're a standalone component
  42. pascal ComponentResult main(ComponentParameters *params, Handle storage)
  43.  
  44. #endif DEBUG_IT
  45.  
  46. {
  47.     // This routine is the main dispatcher for the softVdig
  48.     
  49.     ComponentRoutineUPP    vdigProc = 0;
  50.     ComponentResult err = 0;
  51.  
  52.     if (params->what < 0) {
  53.         switch(params->what) {
  54.             case kComponentOpenSelect:                vdigProc = (ComponentRoutineUPP)vdigOpen; break;
  55.             case kComponentCloseSelect:                vdigProc = (ComponentRoutineUPP)vdigClose; break;
  56.             case kComponentCanDoSelect:                vdigProc = (ComponentRoutineUPP)vdigCanDo; break;
  57.             case kComponentVersionSelect:            vdigProc = (ComponentRoutineUPP)vdigVersion; break;
  58.         }
  59.     }
  60.     else {
  61.         switch (params->what) {
  62.             case kVDGetMaxSrcRectSelect:            vdigProc = (ComponentRoutineUPP)vdigGetMaxSrcRect; break;
  63.             case kVDGetActiveSrcRectSelect:            vdigProc = (ComponentRoutineUPP)vdigGetActiveSrcRect; break;
  64.             case kVDSetDigitizerRectSelect:            vdigProc = (ComponentRoutineUPP)vdigSetDigitizerRect; break;
  65.             case kVDGetDigitizerRectSelect:            vdigProc = (ComponentRoutineUPP)vdigGetDigitizerRect; break;
  66.             case kVDUseThisCLUTSelect:                vdigProc = (ComponentRoutineUPP)vdigUseThisCLUT; break;
  67.             case kVDGrabOneFrameSelect:                vdigProc = (ComponentRoutineUPP)vdigGrabOneFrame; break;
  68.             case kVDGetMaxAuxBufferSelect:            vdigProc = (ComponentRoutineUPP)vdigGetMaxAuxBuffer; break;
  69.             case kVDGetDigitizerInfoSelect:            vdigProc = (ComponentRoutineUPP)vdigGetDigitizerInfo; break;
  70.             case kVDGetCurrentFlagsSelect :            vdigProc = (ComponentRoutineUPP)vdigGetCurrentFlags; break;
  71.             case kVDSetPlayThruDestinationSelect:    vdigProc = (ComponentRoutineUPP)vdigSetPlayThruDestination; break;
  72.             case kVDSetBrightnessSelect :            vdigProc = (ComponentRoutineUPP)vdigSetBrightness; break;
  73.             case kVDGetBrightnessSelect :            vdigProc = (ComponentRoutineUPP)vdigGetBrightness; break;    
  74.             case kVDSetContrastSelect :                vdigProc = (ComponentRoutineUPP)vdigSetContrast; break;            
  75.             case kVDSetHueSelect :                    vdigProc = (ComponentRoutineUPP)vdigSetHue; break;
  76.             case kVDSetSaturationSelect :            vdigProc = (ComponentRoutineUPP)vdigSetSaturation; break;
  77.             case kVDSetSharpnessSelect :            vdigProc = (ComponentRoutineUPP)vdigSetSharpness; break;
  78.             case kVDGetContrastSelect :                vdigProc = (ComponentRoutineUPP)vdigGetContrast; break;
  79.             case kVDGetHueSelect :                    vdigProc = (ComponentRoutineUPP)vdigGetHue; break;
  80.             case kVDGetSaturationSelect :            vdigProc = (ComponentRoutineUPP)vdigGetSaturation; break;
  81.             case kVDGetSharpnessSelect :            vdigProc = (ComponentRoutineUPP)vdigGetSharpness; break;
  82.             case kVDSetBlackLevelValueSelect :        vdigProc = (ComponentRoutineUPP)vdigSetBlackLevel; break;
  83.             case kVDGetBlackLevelValueSelect :        vdigProc = (ComponentRoutineUPP)vdigGetBlackLevel; break;
  84.             case kVDSetWhiteLevelValueSelect :        vdigProc = (ComponentRoutineUPP)vdigSetWhiteLevel; break;
  85.             case kVDGetWhiteLevelValueSelect :        vdigProc = (ComponentRoutineUPP)vdigGetWhiteLevel; break;
  86.             case kVDGetVideoDefaultsSelect :        vdigProc = (ComponentRoutineUPP)vdigGetVideoDefaults; break;    
  87.             case kVDSetPlayThruOnOffSelect:            vdigProc = (ComponentRoutineUPP)vdigSetPlayThruOnOff; break;
  88.             case kVDPreflightDestinationSelect:        vdigProc = (ComponentRoutineUPP)vdigPreflightDestination; break;
  89.             case kVDSetupBuffersSelect:                vdigProc = (ComponentRoutineUPP)vdigSetupBuffers; break;
  90.             case kVDGrabOneFrameAsyncSelect:        vdigProc = (ComponentRoutineUPP)vdigGrabOneFrameAsync; break;
  91.             case kVDDoneSelect:                        vdigProc = (ComponentRoutineUPP)vdigDone; break;
  92.             case kVDGetNumberOfInputsSelect:        vdigProc = (ComponentRoutineUPP)vdigGetNumberOfInputs; break;
  93.             case kVDGetInputFormatSelect:            vdigProc = (ComponentRoutineUPP)vdigGetInputFormat; break;
  94.             case kVDSetInputSelect:                    vdigProc = (ComponentRoutineUPP)vdigSetInput; break;
  95.             case kVDGetInputSelect:                    vdigProc = (ComponentRoutineUPP)vdigGetInput; break;
  96.             case kVDSetCompressionSelect:            vdigProc = (ComponentRoutineUPP)vdigSetCompression; break;
  97.             case kVDCompressOneFrameAsyncSelect:    vdigProc = (ComponentRoutineUPP)vdigCompressOneFrameAsync; break;
  98.             case kVDCompressDoneSelect:                vdigProc = (ComponentRoutineUPP)vdigCompressDone; break;
  99.             case kVDReleaseCompressBufferSelect:    vdigProc = (ComponentRoutineUPP)vdigReleaseCompressBuffer; break;
  100.             case kVDGetImageDescriptionSelect:        vdigProc = (ComponentRoutineUPP)vdigGetImageDescription; break;
  101.             case kVDResetCompressSequenceSelect:    vdigProc = (ComponentRoutineUPP)vdigResetCompressSequence; break;
  102.             case kVDSetCompressionOnOffSelect:        vdigProc = (ComponentRoutineUPP)vdigSetCompressionOnOff; break;
  103.             case kVDGetCompressionTypesSelect:        vdigProc = (ComponentRoutineUPP)vdigGetCompressionTypes; break;
  104.             case kVDSetTimeBaseSelect:                vdigProc = (ComponentRoutineUPP)vdigSetTimeBase; break;
  105.             case kVDSetFrameRateSelect:                vdigProc = (ComponentRoutineUPP)vdigSetFrameRate; break;
  106.             case kVDGetDMADepthsSelect:                vdigProc = (ComponentRoutineUPP)vdigGetDMADepths; break;
  107.             case kVDGetPreferredTimeScaleSelect:    vdigProc = (ComponentRoutineUPP)vdigGetPreferredTimeScale; break;
  108.  
  109.             default:
  110.                         err = digiUnimpErr;
  111.                         break;
  112.         }
  113.     }
  114.  
  115.     if (vdigProc) {
  116.         err = CallComponentFunctionWithStorage((Handle)storage, params, vdigProc);
  117.         
  118.     // kck - for debug only to catch calls that fail
  119.     if (((params->what != kVDSetFrameRateSelect) && 
  120.             (params->what != kVDCompressDoneSelect) && 
  121.             (params->what != kVDGetMaxAuxBufferSelect) &&
  122.             (params->what != kVDUseThisCLUTSelect) && 
  123.             (params->what != kVDSetCompressionOnOffSelect)
  124.             ) && err ) {
  125.             return err;
  126.         }
  127.         return err;
  128.     }
  129.  
  130.     return err;
  131. }
  132.  
  133. #ifdef DEBUG_IT
  134. Component RegisterSoftVdig(void)
  135. {
  136.     ComponentDescription foo;
  137.     Component fooey;
  138.     Handle name;
  139.  
  140.       foo.componentType = videoDigitizerComponentType;
  141.       foo.componentSubType = 'soft';
  142.       foo.componentManufacturer = 'jph ';
  143.       foo.componentFlags = 0L;
  144.       foo.componentFlagsMask = 0L;
  145.  
  146.     PtrToHand ((Ptr)"\psoftVdig (Linked)", &name, 18);
  147.     fooey = RegisterComponent (&foo, (void *)softVdig, 0, name, 0, 0);
  148.     DisposHandle (name);
  149.     SetDefaultComponent (fooey, defaultComponentAnyFlagsAnyManufacturerAnySubType);
  150.  
  151.     return fooey;
  152. }
  153. #endif DEBUG_IT
  154.  
  155. pascal ComponentResult vdigOpen(vdigGlobals storage, ComponentInstance self)
  156. {
  157.     ComponentResult err;
  158.  
  159.     if (CountComponentInstances((Component)self) > (short)gMaxSoftVdigCount)
  160.         return(-1);
  161.  
  162.     storage = (vdigGlobals)NewHandleClear(sizeof(vdigGlobalsRecord));
  163.     if (err = MemError()) goto bail;
  164.     (**storage).self = self;
  165.     SetComponentInstanceStorage(self, (Handle)storage);
  166. #if TARGET_OS_MAC
  167.     SetComponentInstanceA5(self, *(long *)0x904);
  168. #endif
  169.  
  170.     // Initialize some of the global storage members
  171.     err = vdigGetMaxSrcRect(storage, ntscIn, &(**storage).maxSrcRect);
  172.     (**storage).digiRect = (**storage).maxSrcRect;
  173.     (**storage).pendingAsyncBuffer = -1;
  174.     err = vdigGetVideoDefaults(storage,
  175.                              &(**storage).blackLevel, &(**storage).whiteLevel,
  176.                             &(**storage).brightness, &(**storage).hue, &(**storage).saturation,
  177.                             &(**storage).contrast, &(**storage).sharpness);
  178.  
  179. // Initialize two additional softvdig configurable items
  180.     (**storage).gAttachedGDevice = 0;
  181.     MacSetRect(&(**storage).gAuxBufferRect,0,0,300,300);
  182.  
  183.  
  184. bail:
  185.     return(err);
  186. }
  187.  
  188. pascal ComponentResult vdigClose(vdigGlobals storage, ComponentInstance self)
  189. {
  190.     if (storage) {
  191.         if ((**storage).tempPort)
  192.             DisposeGWorld((**storage).tempPort);
  193.  
  194.         if ((**storage).auxBuffer)
  195.             DisposeGWorld((**storage).auxBuffer);
  196.  
  197.         if ((**storage).bufferList)
  198.             DisposeHandle((Handle)(**storage).bufferList);
  199.  
  200.         if ((**storage).clipRgn)
  201.             DisposeRgn((**storage).clipRgn);
  202.  
  203.         tossCompressStuff(storage);
  204.  
  205.         DisposeHandle((Handle)storage);
  206.     }
  207.  
  208.     return noErr;
  209. }
  210.  
  211. pascal ComponentResult vdigCanDo(vdigGlobals storage, short ftnNumber)
  212. {
  213. #define kvdigSelectors kVDSetPreferredPacketSizeSelect
  214.     return (ftnNumber <= kvdigSelectors) && (ftnNumber >= kComponentVersionSelect);
  215. }
  216.  
  217. pascal ComponentResult vdigVersion(vdigGlobals storage)
  218. {
  219.     return (vdigInterfaceRev<<16) | 1;
  220. }
  221.  
  222. pascal VideoDigitizerError vdigGetMaxSrcRect(vdigGlobals storage, short inputStd, Rect *maxSrcRect)
  223. {
  224. long    error = noErr;
  225.  
  226.     if (inputStd == ntscIn)            // softvdig supports only NTSC
  227.         MacSetRect(maxSrcRect, 0, 0, kMaxHorNTSCIn, kMaxVerNTSCIn + kVerBlank);
  228.     else
  229.         error = paramErr;
  230.     if (!error) (**storage).maxSrcRect = *maxSrcRect;
  231.  
  232.     return error;
  233. }
  234.  
  235. pascal VideoDigitizerError vdigGetActiveSrcRect(vdigGlobals storage, short inputStd, Rect *activeSrcRect)
  236. {
  237.     *activeSrcRect = (**storage).maxSrcRect;
  238.  
  239.     return noErr;
  240. }
  241.  
  242. pascal VideoDigitizerError vdigSetDigitizerRect(vdigGlobals storage, Rect *digiRect)
  243. {
  244.     Rect tempR;
  245.  
  246.     // can't be empty
  247.     if (!digiRect || EmptyRect(digiRect))
  248.         return(paramErr);
  249.  
  250.     // they must intersect
  251.     if (!SectRect(digiRect, &(**storage).maxSrcRect, &tempR))
  252.         return(paramErr);
  253.  
  254.     // completely...
  255.     if (!MacEqualRect(digiRect, &tempR))
  256.         return(paramErr);
  257.  
  258.     (**storage).digiRect = *digiRect;
  259.  
  260.     return noErr;
  261. }
  262.  
  263. pascal VideoDigitizerError vdigGetDigitizerRect(vdigGlobals storage, Rect *digiRect)
  264. {
  265.     *digiRect = (**storage).digiRect;
  266.  
  267.     return noErr;
  268. }
  269.  
  270. pascal VideoDigitizerError vdigUseThisCLUT(vdigGlobals storage, CTabHandle colorTableHandle)
  271. {
  272.     return digiUnimpErr;
  273. }
  274.  
  275. void makeOffscreen(vdigGlobals storage)
  276. {
  277.     OSErr err;
  278.     GWorldPtr tempPort;
  279.     Rect r;
  280.  
  281.     tossOffscreen(storage);
  282.  
  283.     if (!(**storage).playThruPixMap) return;
  284.  
  285.     MacSetRect(&r, 0, 0, 4, 4);
  286.     err = NewGWorld(&tempPort, (**(**storage).playThruPixMap).pixelSize, &r, 0, 0, 0);
  287.     if (err) return;
  288.  
  289.     (**storage).tempPort = tempPort;
  290.     MacSetRectRgn(tempPort->visRgn, -32000, -32000, 32000, 32000);
  291. }
  292.  
  293. void tossOffscreen(vdigGlobals storage)
  294. {
  295.     if ((**storage).tempPort) {
  296.         DisposeGWorld((**storage).tempPort);
  297.         (**storage).tempPort = 0;
  298.     }
  299. }
  300.  
  301. void drawVideoFrame(vdigGlobals storage, Point where, PixMapHandle destPixMap)
  302. {
  303.     Rect destRect;
  304.     CGrafPtr savePort;
  305.     GDHandle saveGD;
  306.     PixMapHandle savePortPix;
  307.     Rect pictRect;
  308.     Rect clipRect;
  309.     Str255 tempStr;
  310.     Point offsetClip;
  311.     RgnHandle clipRgn;
  312.     FontInfo    fontInfo;
  313.     short        stringWidth, textSize;
  314.  
  315.     if (!(**storage).tempPort && !(**storage).compressGW) {
  316.         makeOffscreen(storage);
  317.         if (!(**storage).tempPort)
  318.             return;
  319.     }
  320.  
  321.     destRect = (**storage).digiRect;
  322.     TransformRect(&(**storage).matrix, &destRect, 0);
  323.     MacOffsetRect(&destRect, -destRect.left + where.h, -destRect.top + where.v);
  324.  
  325.     GetGWorld(&savePort, &saveGD);
  326.     if ((**storage).compressGW)
  327.         SetGWorld((**storage).compressGW, 0);
  328.     else {
  329.         SetGWorld((**storage).tempPort, 0);
  330.         savePortPix = (**storage).tempPort->portPixMap;
  331.         SetPortPix(destPixMap);
  332.     }
  333.  
  334.     clipRect = (**storage).digiRect;
  335.     ClipRect(&clipRect);
  336.  
  337.     if (clipRgn = (**storage).clipRgn) {
  338.         offsetClip.h = where.h - (**storage).clipOrigin.h;
  339.         offsetClip.v = where.v - (**storage).clipOrigin.v;
  340.         MacOffsetRgn(clipRgn, offsetClip.h, offsetClip.v);
  341.         SetClip(clipRgn);
  342.     }
  343.     else {
  344.         MacSetRect(&clipRect, -32000, -32000, 32000, 32000);
  345.         ClipRect(&clipRect);
  346.     }
  347.  
  348.     clipRect = (**storage).maxSrcRect;
  349.     MapRect(&clipRect, &(**storage).digiRect, &destRect);
  350.  
  351.     pictRect = clipRect;
  352.     EraseRect(&pictRect);
  353.     MacFrameRect(&pictRect);
  354.     MacInsetRect(&pictRect, 10, 10);
  355.     MacFrameRect(&pictRect);
  356.     MacInsetRect(&pictRect, 10, 10);
  357.     TextFont(kFontIDHelvetica);
  358.     textSize = (pictRect.bottom - pictRect.top) >> 1;
  359.     TextSize(textSize);
  360.     NumToString((**storage).frameNumber, tempStr);
  361.     stringWidth = StringWidth(tempStr);
  362.     while (stringWidth > (pictRect.right - pictRect.left))
  363.     {
  364.          textSize /= 2;
  365.         TextSize(textSize);
  366.         NumToString((**storage).frameNumber, tempStr);
  367.         stringWidth = StringWidth(tempStr);
  368.     }
  369.     GetFontInfo(&fontInfo);
  370.     MoveTo((pictRect.left + pictRect.right)/2 - stringWidth/2,
  371.         (pictRect.top + pictRect.bottom)/2 - (fontInfo.ascent+fontInfo.descent)/2 + fontInfo.ascent);
  372.     DrawString(tempStr);
  373.  
  374.     (**storage).frameNumber++;
  375.  
  376.     if (clipRgn) {
  377.         MacOffsetRgn(clipRgn, -offsetClip.h, -offsetClip.v);
  378.         MacSetRect(&clipRect, -32000, -32000, 32000, 32000);
  379.         ClipRect(&clipRect);
  380.     }
  381.  
  382.     if (!(**storage).compressGW)
  383.         SetPortPix(savePortPix);
  384.     SetGWorld(savePort, saveGD);
  385. }
  386.  
  387. pascal VideoDigitizerError vdigGrabOneFrame(vdigGlobals storage)
  388. {
  389.     if (!(**storage).playThruPixMap)
  390.         return badCallOrderErr;
  391.  
  392.     drawVideoFrame(storage, *(Point *)&((**storage).playThruRect), (**storage).playThruPixMap);
  393.  
  394.     return noErr;
  395. }
  396. pascal VideoDigitizerError vdigSetContrast(vdigGlobals storage, unsigned short *contrast)
  397. {
  398.     (**storage).contrast = *contrast;
  399.     return noErr;
  400. }
  401.  
  402. pascal VideoDigitizerError vdigGetContrast(vdigGlobals storage, unsigned short *contrast)
  403. {
  404.     *contrast = (**storage).contrast;
  405.     return noErr;
  406. }
  407.  
  408. pascal VideoDigitizerError vdigSetHue(vdigGlobals storage, unsigned short *hue) {
  409.     (**storage).hue = *hue;
  410.     return noErr;
  411. }
  412. pascal VideoDigitizerError vdigGetHue(vdigGlobals storage, unsigned short *hue)
  413. {
  414.     *hue = (**storage).hue;
  415.     return noErr;
  416. }
  417.  
  418. pascal VideoDigitizerError vdigSetBrightness(vdigGlobals storage, unsigned short *brightness)
  419. {
  420.     (**storage).brightness = *brightness;
  421.     return noErr;
  422. }
  423. pascal VideoDigitizerError vdigGetBrightness(vdigGlobals storage, unsigned short *brightness)
  424. {
  425.     *brightness = (**storage).brightness;
  426.     return noErr;
  427. }
  428.  
  429. pascal VideoDigitizerError vdigSetSaturation(vdigGlobals storage, unsigned short *saturation)
  430. {
  431.     (**storage).saturation = *saturation;
  432.     return noErr;
  433. }
  434.  
  435. pascal VideoDigitizerError vdigGetSaturation(vdigGlobals storage, unsigned short *saturation)
  436. {
  437.     *saturation = (**storage).saturation;
  438.     return noErr;
  439. }
  440. pascal VideoDigitizerError vdigSetSharpness(vdigGlobals storage, unsigned short *sharpness)
  441. {
  442.     (**storage).sharpness = *sharpness;
  443.     return noErr;
  444. }
  445.  
  446. pascal VideoDigitizerError vdigGetSharpness(vdigGlobals storage, unsigned short *sharpness)
  447. {
  448.     *sharpness = (**storage).sharpness;
  449.     return noErr;
  450. }
  451.  
  452. pascal VideoDigitizerError vdigSetBlackLevel(vdigGlobals storage, unsigned short *blackLevel)
  453. {
  454.     (**storage).blackLevel = *blackLevel;
  455.     return noErr;
  456. }
  457. pascal VideoDigitizerError vdigGetBlackLevel(vdigGlobals storage, unsigned short *blackLevel)
  458. {
  459.     *blackLevel = (**storage).blackLevel;
  460.     return noErr;
  461. }
  462. pascal VideoDigitizerError vdigSetWhiteLevel(vdigGlobals storage, unsigned short *whiteLevel)
  463. {
  464.     (**storage).whiteLevel = *whiteLevel;
  465.     return noErr;
  466. }
  467. pascal VideoDigitizerError vdigGetWhiteLevel(vdigGlobals storage, unsigned short *whiteLevel){
  468.     *whiteLevel = (**storage).whiteLevel;
  469.     return noErr;
  470. }
  471. pascal VideoDigitizerError vdigGetVideoDefaults(vdigGlobals storage,
  472.                             unsigned short *blackLevel, unsigned short *whiteLevel,
  473.                             unsigned short *brightness, unsigned short *hue, unsigned short *saturation,
  474.                             unsigned short *contrast, unsigned short *sharpness)
  475. {
  476.     (**storage).blackLevel     = 0;
  477.     (**storage).whiteLevel     = 60000;
  478.     (**storage).brightness     = 20000;
  479.     (**storage).hue         = 30000;
  480.     (**storage).saturation     = 40000;
  481.     (**storage).contrast     = 50000;
  482.     (**storage).sharpness     = 60000;
  483.     return noErr;
  484. }
  485.  
  486. pascal VideoDigitizerError vdigGetMaxAuxBuffer(vdigGlobals storage, PixMapHandle *pm, Rect *r)
  487. {
  488.     OSErr     err = noErr;
  489.  
  490.     if (!gHasAuxBuffer)
  491.         return digiUnimpErr;
  492.  
  493.     if (!(**storage).auxBuffer) {
  494.         GWorldPtr tempGW;
  495.  
  496.         err = NewGWorld(&tempGW, gAuxDepth, &(**storage).gAuxBufferRect, 0, 0, 0);
  497.         if (err) goto bail;
  498.  
  499.         LockPixels(tempGW->portPixMap);
  500.  
  501.         (**storage).auxBuffer = tempGW;
  502.     }
  503.  
  504.     if (pm) *pm = (**storage).auxBuffer->portPixMap;
  505.     if (r) *r = (**(**storage).auxBuffer->portPixMap).bounds;
  506.  
  507. bail:
  508.     return err;
  509. }
  510.  
  511. pascal VideoDigitizerError vdigGetDigitizerInfo(vdigGlobals storage, DigitizerInfo *info)
  512. {
  513.     
  514.     info->vdigType = gCanClip ? vdTypeMask : vdTypeBasic;
  515.     info->inputCapabilityFlags = digiInDoesNTSC | digiInDoesComposite | digiInDoesColor;
  516.     info->outputCapabilityFlags = gDoesDepths |
  517.                                 (gCanScale ? digiOutDoesStretch | digiOutDoesShrink : digiOutDoesQuarter | digiOutDoesSixteenth) | 
  518.                                 (gCanClip ? digiOutDoesMask : 0) |
  519.                                 (gCanDMA ? digiOutDoesHW_DMA : 0) |
  520.                                 (gDoesPlaythru ? digiOutDoesHWPlayThru : 0) |
  521.                                 (gCanAsync ? digiOutDoesAsyncGrabs : 0) |
  522.                                 (gDoesCompress ? digiOutDoesCompress : 0) |
  523.                                 ((gDoesCompress && gOnlyDoesCompress) ? digiOutDoesCompressOnly : 0)
  524.                                 ;
  525.  
  526.     info->inputCurrentFlags = info->inputCapabilityFlags;
  527.     info->inputCurrentFlags |= digiInSignalLock;
  528.     info->outputCurrentFlags = 0;
  529.     if ((**storage).gAttachedGDevice)
  530.         info->outputCurrentFlags = (**(**(**storage).gAttachedGDevice).gdPMap).pixelSize;
  531.     else {
  532.  
  533.     }
  534.  
  535.     info->slot = 0;                                // we have no slot
  536.     info->gdh = (**storage).gAttachedGDevice;
  537.     info->maskgdh = 0;                            
  538.     info->minDestHeight = gMinHeight;
  539.     info->minDestWidth = gMinWidth;
  540.     info->maxDestHeight = gMaxHeight;
  541.     info->maxDestWidth = gMaxWidth;
  542.     info->blendLevels = 0;
  543.     info->reserved = 0;
  544.     
  545.     (**storage).inputCurrentFlags  = info->inputCurrentFlags;
  546.     (**storage).outputCurrentFlags = info->outputCurrentFlags;
  547.     
  548.     return noErr;
  549. }
  550. pascal VideoDigitizerError    vdigGetCurrentFlags(vdigGlobals storage, long *inputCurrentFlag, long *outputCurrentFlag) 
  551. {
  552.     *inputCurrentFlag = (**storage).inputCurrentFlags;
  553.     *outputCurrentFlag = (**storage).outputCurrentFlags;
  554.     return noErr;
  555. }
  556.  
  557. pascal VideoDigitizerError vdigSetPlayThruOnOff(vdigGlobals storage, short state)
  558. {
  559.     if (!gDoesPlaythru)
  560.         return digiUnimpErr;
  561.  
  562.     (**storage).playThruOn = (state != 0);
  563.     return noErr;
  564. }
  565.  
  566. pascal VideoDigitizerError vdigSetPlayThruDestination(vdigGlobals storage, PixMapHandle dest, Rect *dr, MatrixRecord *m, RgnHandle mask)
  567. {
  568.     OSErr err;
  569.     short width, height;
  570.     Rect destRect;
  571.  
  572.     if (!dest || (!dr && !m))
  573.         return paramErr;
  574.  
  575.     if (dr)
  576.         destRect = *dr;
  577.     else {
  578.         if (GetMatrixType(m) > scaleTranslateMatrixType)
  579.             return matrixErr;
  580.         destRect = (**storage).digiRect;
  581.         TransformRect(m, &destRect, nil);
  582.     }
  583.  
  584.     // make sure the rectangle is ok
  585.     if (EmptyRect(&destRect))
  586.         return paramErr;
  587.  
  588.     if (mask && !gCanClip)
  589.         return paramErr;
  590.  
  591.     if (!validatePixMap(storage, dest))
  592.         return paramErr;
  593.  
  594.     if ((**storage).clipRgn) {
  595.         DisposeRgn((**storage).clipRgn);
  596.         (**storage).clipRgn = 0;
  597.     }
  598.  
  599.     if (mask) {
  600.         HandToHand((Handle *)&mask);
  601.         if (err = MemError()) return err;
  602.     }
  603.     (**storage).clipRgn = mask;
  604.     (**storage).clipOrigin = *(Point *)&destRect;
  605.  
  606.     {
  607.     Rect tempRect;
  608.  
  609.     tempRect = destRect;
  610.     MapRect(&tempRect, &(**storage).digiRect, &(**storage).maxSrcRect);            // convert to full frame
  611.     RectMatrix(&(**storage).matrix, &(**storage).maxSrcRect, &tempRect);        // make a matrix
  612.  
  613.     tempRect = (**storage).maxSrcRect;
  614.     TransformRect(&(**storage).matrix, &tempRect, 0);
  615.     width = tempRect.right - tempRect.left;
  616.     height = tempRect.bottom - tempRect.top;
  617.     }
  618.  
  619.     if (width < gMinWidth || width > gMaxWidth || height < gMinHeight || height > gMaxHeight)
  620.         return paramErr;
  621.  
  622. #if 0
  623.     if (width != gMaxWidth || height != gMaxHeight)
  624.         return paramErr;
  625. #endif
  626.  
  627.     if (!gCanScale) {
  628.         short i = 3;
  629.         short tempWidth = gMaxWidth;
  630.         short tempHeight = gMaxHeight;
  631.         Boolean ok;
  632.  
  633.         while (i--) {
  634.             ok = (width == tempWidth) && (height == tempHeight);
  635.             if (ok) break;
  636.             tempWidth >>= 1;
  637.             tempHeight >>= 1;
  638.         }
  639.         if (!ok)
  640.             return paramErr;
  641.     }
  642.  
  643.     if ((**storage).tempPort) {
  644.         if ((**dest).pixelSize != (**(**storage).tempPort->portPixMap).pixelSize)
  645.             tossOffscreen(storage);
  646.     }
  647.  
  648.     (**storage).playThruRect = destRect;
  649.     (**storage).playThruPixMap = dest;
  650.  
  651.     return noErr;
  652. }
  653.  
  654. // better checks for pixmap baseAddr matching could be done
  655. Boolean validatePixMap(vdigGlobals storage, PixMapHandle p)
  656. {
  657.     if ( !((**p).pixelSize & gDoesDepths) ) {
  658.         if (gCanDMA && ((**p).pixelSize & gDMADepths))
  659.             ;
  660.         else
  661.             return false;
  662.     }
  663.  
  664.     if (gCanDMA)                        // any other place is OK
  665.         return true;
  666.  
  667.     if ((**storage).gAttachedGDevice) {
  668.         // see if pixels are on the device
  669.         if ((**p).baseAddr == (**(**(**storage).gAttachedGDevice).gdPMap).baseAddr)
  670.             return true;
  671.     }
  672.  
  673.     if ((**storage).auxBuffer) {
  674.         if ((**p).baseAddr == (**(**storage).auxBuffer->portPixMap).baseAddr)
  675.             return true;
  676.     }
  677.  
  678.     if (!(**storage).gAttachedGDevice) return true;
  679.  
  680.     return false;
  681. }
  682.  
  683. pascal VideoDigitizerError vdigPreflightDestination(vdigGlobals storage, Rect *digitizerRect, PixMap **dest, Rect *destRect, MatrixRecord *m)
  684. {
  685.     //••  real code is required here in your vdig!!
  686.  
  687.     return noErr;
  688. }
  689.  
  690. pascal VideoDigitizerError vdigSetupBuffers(vdigGlobals storage, VdigBufferRecListHandle bufferList)
  691. {
  692.     OSErr err;
  693.     MatrixRecord matrix;
  694.     short i;
  695.     RgnHandle clipRgn;
  696.  
  697.     if (!bufferList)
  698.         return paramErr;
  699.  
  700.     if (!(**bufferList).count)
  701.         return paramErr;
  702.  
  703.     if ((**storage).bufferList) {
  704.         DisposeHandle((Handle)(**storage).bufferList);
  705.         (**storage).bufferList = 0;
  706.     }
  707.  
  708.     if ((**storage).clipRgn) {
  709.         DisposeRgn((**storage).clipRgn);
  710.         (**storage).clipRgn = 0;
  711.     }
  712.  
  713.     if (!gCanClip && (**bufferList).mask)
  714.         return paramErr;
  715.  
  716.     if ((**bufferList).matrix)
  717.         matrix = *(**bufferList).matrix;
  718.  
  719.     // make a local copy of the buffer list
  720.     HandToHand((Handle *)&bufferList);
  721.     if (err = MemError()) return err;
  722.  
  723.     if (clipRgn = (**bufferList).mask) {
  724.         HandToHand((Handle *)&clipRgn);
  725.         if (err = MemError()) return err;
  726.         (**storage).clipOrigin = (**bufferList).list[0].location;
  727.     }
  728.  
  729.     (**storage).bufferList = bufferList;
  730.     (**storage).clipRgn = clipRgn;
  731.     (**storage).pendingAsyncBuffer = -1;
  732.     (**storage).matrix = matrix;
  733.  
  734.     for (i=0; i < (**bufferList).count; i++) {    
  735.         if (!validatePixMap(storage, (**bufferList).list[i].dest))
  736.             return paramErr;
  737.         // should check the point here too
  738.     }
  739.  
  740.     return noErr;
  741. }
  742.  
  743. pascal VideoDigitizerError vdigGrabOneFrameAsync(vdigGlobals storage, short buffer)
  744. {
  745.     VdigBufferRecListHandle bufferList;
  746.  
  747.     if (!gCanAsync)
  748.         return digiUnimpErr;
  749.  
  750.     if (!(bufferList = (**storage).bufferList))
  751.         return badCallOrderErr;
  752.  
  753.     if (buffer > (**bufferList).count)
  754.         return paramErr;
  755.  
  756.     if ((**storage).pendingAsyncBuffer != -1) {
  757.         short aBuf = (**storage).pendingAsyncBuffer;
  758.  
  759. #if HAVE_DEBUGSTR
  760.         if (aBuf == buffer)
  761.             DebugStr("\pasync grab into incomplete buffer");
  762. #endif
  763.  
  764.         drawVideoFrame(storage, (**bufferList).list[aBuf].location, (**bufferList).list[aBuf].dest);
  765.     }
  766.  
  767.     (**storage).pendingAsyncBuffer = buffer;
  768.  
  769.     return noErr;
  770. }
  771.  
  772. pascal long    vdigDone(vdigGlobals storage, short buffer)
  773. {
  774.     vdigGlobalsPtr store = *storage;
  775.     VdigBufferRecListHandle bufferList;
  776.  
  777.     if (!gCanAsync)
  778.         return 0;
  779.  
  780.     if (!(bufferList = store->bufferList))
  781.         return 0;
  782.  
  783.     if (buffer > (**bufferList).count)
  784.         return 0;
  785.  
  786.     if (store->frameTimeStep && GetTimeBaseRate(store->timeBase)) {
  787.         if (GetTimeBaseTime(store->timeBase, gVideoTimeScale ? gVideoTimeScale : 600, nil) >= store->nextFrameTime)
  788.             store->nextFrameTime += store->frameTimeStep;
  789.         else
  790.             return false;
  791.     }
  792.  
  793.     if (store->pendingAsyncBuffer == buffer) {
  794.         drawVideoFrame(storage, (**bufferList).list[buffer].location, (**bufferList).list[buffer].dest);
  795.         store->pendingAsyncBuffer = -1;
  796.     }
  797.  
  798.     return true;
  799. }
  800.  
  801. /*
  802.     inputs garbage
  803. */
  804.  
  805. pascal VideoDigitizerError vdigGetNumberOfInputs(vdigGlobals storage, short *inputs)
  806. {
  807.     *inputs = 0;
  808.  
  809.     return noErr;
  810. }
  811.  
  812. pascal VideoDigitizerError vdigGetInputFormat(vdigGlobals storage, short input, short *format)
  813. {
  814.     if (input == 0) {
  815.         *format = ntscIn;
  816.         return noErr;
  817.     }
  818.     else
  819.         return paramErr;
  820. }
  821.  
  822. pascal VideoDigitizerError vdigSetInput(vdigGlobals storage, short input)
  823. {
  824.     if (input == 0)
  825.         return noErr;
  826.     else
  827.         return paramErr;
  828. }
  829.  
  830. pascal VideoDigitizerError vdigGetInput(vdigGlobals storage, short *input)
  831. {
  832.     *input = 0;
  833.  
  834.     return noErr;
  835. }
  836.  
  837. /*
  838.     compressed source stuff
  839. */
  840.  
  841. void tossCompressStuff(vdigGlobals storage)
  842. {
  843.     if ((**storage).compressSeq) {
  844.         CDSequenceEnd((**storage).compressSeq);
  845.         (**storage).compressSeq = 0;
  846.     }
  847.  
  848.     if ((**storage).compressGW) {
  849.         DisposeGWorld((**storage).compressGW);
  850.         (**storage).compressGW = 0;
  851.     }
  852.  
  853.     if ((**storage).compressBuffer) {
  854.         DisposePtr((**storage).compressBuffer);
  855.         (**storage).compressBuffer = 0;
  856.     }
  857.  
  858.     if ((**storage).desc) {
  859.         DisposeHandle((Handle)(**storage).desc);
  860.         (**storage).desc = 0;
  861.     }
  862. }
  863.  
  864.  
  865. pascal VideoDigitizerError vdigSetCompression(vdigGlobals storage, OSType compressType, short depth, Rect *bounds,
  866.             CodecQ spatialQuality, CodecQ temporalQuality, long keyFrameRate)
  867. {
  868.     OSErr err;
  869.     GWorldPtr gw = 0;
  870.     long bufSize;
  871.     Ptr p;
  872.     ImageDescription ** tempImageDesc;
  873.     ImageSequence tempSeqId;
  874.  
  875.     if (!gDoesCompress)
  876.         return digiUnimpErr;
  877.  
  878.     tossCompressStuff(storage);
  879.  
  880.     if (compressType == 'vpza')
  881.         compressType = 'rpza';
  882.  
  883.     // see if we handle this compression
  884.     if (compressType && gOnlyCompressType && 
  885.         (compressType != gOnlyCompressType))
  886.         return noCodecErr;
  887.  
  888.     if (!compressType) {
  889.         compressType = gOnlyCompressType ? gOnlyCompressType : 'rpza';
  890.         spatialQuality = codecNormalQuality;
  891.         temporalQuality = 0;
  892.         keyFrameRate = 0;
  893.     }
  894.  
  895.     (**storage).compressType = compressType;
  896.     (**storage).compressDepth = depth ? depth : 16;
  897.     (**storage).compressRect = *bounds;
  898.     (**storage).spatialQuality = spatialQuality;
  899.     (**storage).temporalQuality = temporalQuality;
  900.     (**storage).keyFrameRate = keyFrameRate;
  901.  
  902.     if (compressType == -1)
  903.         return noErr;
  904.  
  905.     {
  906.     Rect tempRect;
  907.  
  908.     tempRect = *bounds;
  909.     MapRect(&tempRect, &(**storage).digiRect, &(**storage).maxSrcRect);            // convert to full frame
  910.     RectMatrix(&(**storage).matrix, &(**storage).maxSrcRect, &tempRect);        // make a matrix
  911.     }
  912.  
  913.     err = NewGWorld(&gw, depth, bounds, 0, 0, 0);
  914.     if (err) goto bail;
  915.     (**storage).compressGW = gw;
  916.     LockPixels(gw->portPixMap);
  917.  
  918.     err = GetMaxCompressionSize(gw->portPixMap, bounds, depth, spatialQuality, compressType, bestSpeedCodec, &bufSize);
  919.     if (err) goto bail;
  920.  
  921.     p = NewPtr(bufSize);
  922.     if (err = MemError())  goto bail;
  923.     (**storage).compressBuffer = p;
  924.  
  925.     tempImageDesc = (ImageDescription **)NewHandle(sizeof(ImageDescription));
  926.     if (err = MemError()) goto bail;
  927.     (**storage).desc = tempImageDesc;
  928.  
  929.     // fill this out for now.. mark will help us out later
  930.     (**tempImageDesc).temporalQuality = temporalQuality;
  931.     (**tempImageDesc).spatialQuality = spatialQuality;
  932.     (**tempImageDesc).width = bounds->right - bounds->left;
  933.     (**tempImageDesc).height = bounds->bottom - bounds->top;
  934.     (**tempImageDesc).depth = (compressType == 'rpza') ? 16 : depth;
  935.     (**tempImageDesc).cType = compressType;
  936.     (**tempImageDesc).hRes = 0x00480000;
  937.     (**tempImageDesc).vRes = 0x00480000;
  938.  
  939.     err = CompressSequenceBegin(&tempSeqId,
  940.                     gw->portPixMap, (PixMap **)0,
  941.                     bounds, (Rect *)0,
  942.                     depth, compressType, bestSpeedCodec, spatialQuality, 
  943.                     temporalQuality, keyFrameRate, (CTabHandle )0,
  944.                     codecFlagUpdatePrevious, tempImageDesc );
  945.     if (err) goto bail;
  946.  
  947.     (**storage).compressSeq = tempSeqId;
  948.  
  949. bail:
  950.     if (err)
  951.         tossCompressStuff(storage);
  952.  
  953.     return err;
  954. }
  955.  
  956. pascal VideoDigitizerError vdigCompressOneFrameAsync(vdigGlobals storage)
  957. {
  958.     if (!gDoesCompress)
  959.         return digiUnimpErr;
  960.  
  961.     if (!(**storage).compressSeq)
  962.         return badCallOrderErr;
  963.  
  964.     // draw the offscreen now, compress later...
  965.     drawVideoFrame(storage, *(Point *)&(**storage).compressRect, (**storage).compressGW->portPixMap);
  966.  
  967.     return noErr;
  968. }
  969.  
  970. pascal VideoDigitizerError vdigCompressDone(vdigGlobals storage, Boolean *done, Ptr *theData, long *dataSize, unsigned char *similarity, TimeRecord *tr)
  971. {
  972.     vdigGlobalsPtr store = *storage;
  973.     OSErr err;
  974.     Rect r;
  975.  
  976.     *done = true;
  977.  
  978.     if (!gDoesCompress)
  979.         return digiUnimpErr;
  980.  
  981.     if (!store->compressSeq)
  982.         return badCallOrderErr;
  983.  
  984.     if (store->frameTimeStep && GetTimeBaseRate(store->timeBase)) {
  985.         if (GetTimeBaseTime(store->timeBase, gVideoTimeScale ? gVideoTimeScale : 600, nil) >= store->nextFrameTime)
  986.             store->nextFrameTime += store->frameTimeStep;
  987.         else {
  988.             *done = false;
  989.             return noErr;
  990.         }
  991.     }
  992.  
  993.     r = store->compressRect;
  994. /*
  995. extern pascal OSErr CompressSequenceFrame(ImageSequence seqID, PixMapHandle src, const Rect *srcRect, 
  996.                                           CodecFlags flags, Ptr data, long *dataSize, UInt8 *similarity, 
  997.                                           ICMCompletionProcRecordPtr asyncCompletionProc)
  998. */
  999.     err = (OSErr)CompressSequenceFrame(store->compressSeq, store->compressGW->portPixMap, &r,
  1000.                             codecFlagUpdatePrevious | (store->forceKeyFrame ? codecFlagForceKeyFrame : 0),
  1001.                             store->compressBuffer, 
  1002.                             dataSize, 
  1003.                             similarity, 
  1004.                             (ICMCompletionProcRecordPtr)0);
  1005.     store = *storage;
  1006.     *theData = store->compressBuffer;
  1007.  
  1008.     store->forceKeyFrame = false;
  1009.  
  1010.     GetTimeBaseTime(store->timeBase, 30, tr);
  1011.  
  1012.     return err;
  1013. }
  1014.  
  1015. pascal VideoDigitizerError vdigReleaseCompressBuffer(vdigGlobals storage, Ptr theBufffer)
  1016. {
  1017.     if (!gDoesCompress)
  1018.         return digiUnimpErr;
  1019.  
  1020.     if (!(**storage).compressSeq)
  1021.         return badCallOrderErr;
  1022.  
  1023.     //•• could actually track this...
  1024.     //•• could pound part of buffer to 0 or something
  1025.  
  1026.     return noErr;
  1027. }
  1028.  
  1029.  
  1030. pascal VideoDigitizerError vdigGetImageDescription(vdigGlobals storage, ImageDescriptionHandle desc)
  1031. {
  1032.     OSErr err = noErr;
  1033.  
  1034.     if (!gDoesCompress)
  1035.         return digiUnimpErr;
  1036.  
  1037.     if ((**storage).desc) {
  1038.         long dataSize;
  1039.  
  1040.         SetHandleSize((Handle)desc, dataSize = GetHandleSize((Handle)(**storage).desc));
  1041.         if (err = MemError()) goto bail;
  1042.         BlockMove((Ptr)*(**storage).desc, (Ptr)*desc, dataSize);
  1043.     }
  1044.     else
  1045.         err = badCallOrderErr;
  1046.  
  1047. bail:
  1048.     return err;
  1049. }
  1050.  
  1051. pascal VideoDigitizerError vdigResetCompressSequence(vdigGlobals storage)
  1052. {
  1053.     OSErr err = noErr;
  1054.  
  1055.     if (!gDoesCompress)
  1056.         return digiUnimpErr;
  1057.  
  1058.     (**storage).forceKeyFrame = true;
  1059.  
  1060.     return err;
  1061. }
  1062.  
  1063. pascal VideoDigitizerError vdigSetCompressionOnOff(vdigGlobals storage, Boolean newState)
  1064. {
  1065.     OSErr err = noErr;
  1066.  
  1067.     if (!gDoesCompress)
  1068.         return digiUnimpErr;
  1069.  
  1070.     if (newState != (**storage).compressOn) {
  1071.         (**storage).compressOn = newState;
  1072.         if (!(**storage).compressOn)
  1073.             tossCompressStuff(storage);
  1074.     }
  1075.  
  1076.     return err;
  1077. }
  1078.  
  1079. pascal VideoDigitizerError vdigGetCompressionTypes(vdigGlobals storage, VDCompressionListHandle h)
  1080. {
  1081.     CodecInfo info;
  1082.     VDCompressionListPtr p;
  1083.  
  1084.     GetCodecInfo(&info, 'rpza',  0);
  1085.     SetHandleSize((Handle)h, sizeof(VDCompressionList));
  1086.     p = &(*h)[0];
  1087.     BlockMove(info.typeName, p->typeName, 32);
  1088.     p->typeName[++p->typeName[0]] = ' ';
  1089.     p->typeName[++p->typeName[0]] = 'V';
  1090.     p->typeName[++p->typeName[0]] = 'D';
  1091.     p->typeName[++p->typeName[0]] = 'I';
  1092.     p->typeName[++p->typeName[0]] = 'G';
  1093.     BlockMove(p->typeName, p->name, 64);
  1094.     p->codec = 0;
  1095.     p->cType = 'rpza';
  1096.     p->formatFlags = info.formatFlags;
  1097.     p->compressFlags = info.compressFlags;
  1098.  
  1099.     return noErr;
  1100. }
  1101.  
  1102. pascal VideoDigitizerError vdigSetTimeBase(vdigGlobals storage, TimeBase t)
  1103. {
  1104.     (**storage).timeBase = t;
  1105.     return noErr;
  1106. }
  1107.  
  1108. pascal VideoDigitizerError vdigSetFrameRate(vdigGlobals storage, Fixed framesPerSecond)
  1109. {
  1110.     vdigGlobalsPtr store = *storage;
  1111.  
  1112.     if (!gDoesFrameRate)
  1113.         return digiUnimpErr;
  1114.  
  1115.     if (framesPerSecond < 0)
  1116.         return paramErr;
  1117.  
  1118.     store->nextFrameTime = store->frameTimeStep = 0;
  1119.     if (framesPerSecond)
  1120.         store->frameTimeStep = FixDiv(gVideoTimeScale ? gVideoTimeScale : 600, framesPerSecond);
  1121.  
  1122.     return noErr;
  1123. }
  1124.  
  1125. pascal VideoDigitizerError vdigGetDMADepths(vdigGlobals storage, long *depthArray, long *preferredDepth)
  1126. {
  1127.     if (!gCanDMA)
  1128.         return paramErr;
  1129.  
  1130.     *depthArray = gDMADepths;
  1131.     *preferredDepth = 40;
  1132.  
  1133.     return noErr;
  1134. }
  1135.  
  1136. pascal VideoDigitizerError vdigGetPreferredTimeScale(vdigGlobals storage, TimeScale *preferred)
  1137. {
  1138.     if (gVideoTimeScale) {
  1139.         *preferred = gVideoTimeScale;
  1140.         return noErr;
  1141.     }
  1142.     else
  1143.         return badComponentSelector;
  1144. }
  1145.  
  1146.